<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    
    <meta name="author" content="xiaoeryu">
    <!-- preconnect -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    
    <!--- Seo Part-->
    
    <link rel="canonical" href="https://xiaoeeyu.github.io/2022/12/11/29-协同式任务切换/"/>
    <meta name="robots" content="index,follow">
    <meta name="googlebot" content="index,follow">
    <meta name="revisit-after" content="1 days">
    
    
    
        
        <meta name="description" content="01. 任务和任务切换概述多任务系统中，每个任务都有自己的任务状态段TSS和局部描述符表LDT，当前任务是由任务寄存器TR指示，指向当前任务的任务状态段TSS、局部描述符表寄存器LDTR也指向当前局部描述符表LDT。">
<meta property="og:type" content="article">
<meta property="og:title" content="协同式任务切换">
<meta property="og:url" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/index.html">
<meta property="og:site_name" content="xiaoeryu">
<meta property="og:description" content="01. 任务和任务切换概述多任务系统中，每个任务都有自己的任务状态段TSS和局部描述符表LDT，当前任务是由任务寄存器TR指示，指向当前任务的任务状态段TSS、局部描述符表寄存器LDTR也指向当前局部描述符表LDT。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ecaeb5708d898aabbeb7135046099657-166832967486710.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/dcc158c41bd25560420ed9ac91e93f1f-16683296748674.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/5c5fc3fa7fc5bf7b45bc94e33216aae7-16683296748671.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/9338fcfaa209df58ccd8cec9796059a9-16683296748672.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/00af7da67920361a23086cf9741893e9-16683296748673.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/da3677ea1fab46deb7cd37f467754371-16683296748675.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/d0448a72f4c8a35a954f62f55b5e880c-16683296748676.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/c00656182066503226da7f091421e2e7-16683296748679.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/2e1ea44696421df22f3de6cd05dc5fb3-16683296748677.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/f6e06e2f34d89404d6261e892f7ce7a8-16683296748678.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/b877b21342d7e33e4f1c856eb51594ae-166832967486711.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/91176a8596b09cbe9383b772a9bf48a4-166832967486712.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/d251cfc7ef40c8161ed1675c33700695-166832967486714.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/acf15bb6736f7490e9dcfd1a55b9f4d8-166832967486713.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/718352e49749237d68e1c4ba568a88a1-166832967486715.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/41bea40aa66420d64e1fdbac1aa21dc5-166832967486716.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/bbef20148f7a47065143878328f53ea9-166832967486717.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/9e36bd13dc99727a853f3386f567ae47-166832967486718.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/49ba689fa14560fdabc76ff3a3d24938-166832967486819.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ac052aceeb0186b956372984e4100f67-166832967486820.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/dc6036897ff49aeebec6d08d4e222444-166832967486821.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/0bd3c3d8808b9315f7a79ceb4e3209a5-166832967486822.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ff8895b5ee0a42a472ea2ed58c2914cc-166832967486823.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/67391e2a303f4dec1de5a884b13b9704-166832967486824.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ef823bfa7f5ca793b66e36664ede8de5-166832967486825.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/1ff6610bde8ec0dea0d453b3b7f8513b-166832967486826.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/3135d4b33d7c48116f2f6bf55cd66f78-166832967486828.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/a9ab3530a487a16867948ba0c25cf83d-166832967486827.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/001d7c469b6f0b1abc71c9e0f9713cd5-166832967486831.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/39a8a20c8af636fab0a1f4563c1b9bad-166832967486829.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/77fb6ce6c965082e6d67af30c2154161-166832967486830.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/b6b82d293be287f02f228efc14995d42-166832967486834.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/9be2c12d07936a3550453e7f55b65580-166832967486832.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/a65a44442dca24365dd94997b837543d-166832967486833.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/d41c66dea07be9c7e5c05748e71cde5a-166832967486835.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/bd85ede83741a94c9123371a21ebb6db-166832967486836.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/1dcaf8e5bb7db4a65880bcd7c3e953af-166832967486837.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/107c4944925dba82aa648298b8137c5d-166832967486838.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/01869b2eb6e10f8d5cae7caf15c17de4-166832967486839.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/fc427ef9510f44f38d1e12e15be5648a-166832967486840.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/70577bd2c49d9b5eb881ad75b116415d-166832967486841.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/image-20221113165458658.png">
<meta property="article:published_time" content="2022-12-11T14:47:00.000Z">
<meta property="article:modified_time" content="2023-10-03T05:00:13.978Z">
<meta property="article:author" content="xiaoeryu">
<meta property="article:tag" content="x86协同式任务切换">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://xiaoeeyu.github.io/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ecaeb5708d898aabbeb7135046099657-166832967486710.png">
    
    
    <!--- Icon Part-->
    <link rel="icon" type="image/png" href="/images/rabete.jpg" sizes="192x192">
    <link rel="apple-touch-icon" sizes="180x180" href="/images/rabete.jpg">
    <meta name="theme-color" content="#A31F34">
    <link rel="shortcut icon" href="/images/rabete.jpg">
    <!--- Page Info-->
    
    <title>
        
            协同式任务切换 | xiaoeryu
        
    </title>

    
<link rel="stylesheet" href="/fonts/Chillax/chillax.css">


    <!--- Inject Part-->
    

    
<link rel="stylesheet" href="/css/style.css">


    
        
<link rel="stylesheet" href="/css/build/tailwind.css">

    

    
<link rel="stylesheet" href="/fonts/GeistMono/geist-mono.css">

    
<link rel="stylesheet" href="/fonts/Geist/geist.css">

    <!--- Font Part-->
    
    
    
    
    
    

    <script id="hexo-configurations">
    window.config = {"hostname":"xiaoeeyu.github.io","root":"/","language":"zh-CN","path":"search.xml"};
    window.theme = {"articles":{"style":{"font_size":"16px","line_height":1.5,"image_border_radius":"14px","image_alignment":"center","image_caption":false,"link_icon":true,"delete_mask":false,"title_alignment":"left","headings_top_spacing":{"h1":"3.2rem","h2":"2.4rem","h3":"1.9rem","h4":"1.6rem","h5":"1.4rem","h6":"1.3rem"}},"word_count":{"enable":true,"count":true,"min2read":true},"author_label":{"enable":true,"auto":false,"list":[]},"code_block":{"copy":true,"style":"mac","highlight_theme":{"light":"github","dark":"vs2015"},"font":{"enable":false,"family":null,"url":null}},"toc":{"enable":true,"max_depth":4,"number":false,"expand":true,"init_open":true},"copyright":{"enable":true,"default":"cc_by_nc_sa"},"lazyload":true,"pangu_js":false,"recommendation":{"enable":false,"title":"推荐阅读","limit":3,"mobile_limit":2,"placeholder":"/images/ball-0101.jpg","skip_dirs":[]}},"colors":{"primary":"#A31F34","secondary":null,"default_mode":"light"},"global":{"fonts":{"chinese":{"enable":false,"family":null,"url":null},"english":{"enable":false,"family":null,"url":null},"title":{"enable":false,"family":null,"url":null}},"content_max_width":"1000px","sidebar_width":"210px","hover":{"shadow":true,"scale":false},"scroll_progress":{"bar":false,"percentage":true},"website_counter":{"url":"https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js","enable":true,"site_pv":true,"site_uv":true,"post_pv":true},"single_page":true,"preloader":{"enable":false,"custom_message":null},"open_graph":true,"google_analytics":{"enable":false,"id":null}},"home_banner":{"enable":true,"style":"fixed","image":{"light":"/images/wallhaven-jxl31y.png","dark":"/images/wallhaven-o5762l.png"},"title":"XIAOERYU","subtitle":{"text":["明心见性，拨云见日","Don't wait, to create"],"hitokoto":{"enable":false,"show_author":false,"api":"https://v1.hitokoto.cn"},"typing_speed":100,"backing_speed":80,"starting_delay":500,"backing_delay":1500,"loop":true,"smart_backspace":true},"text_color":{"light":"#fff","dark":"#d1d1b6"},"text_style":{"title_size":"2.8rem","subtitle_size":"1.5rem","line_height":1.2},"custom_font":{"enable":false,"family":null,"url":null},"social_links":{"enable":true,"style":"default","links":{"github":"https://github.com/xiaoeeyu","instagram":null,"zhihu":null,"twitter":null,"email":"xiaoeryu@163.com"},"qrs":{"weixin":null}}},"plugins":{"feed":{"enable":false},"aplayer":{"enable":false,"type":"fixed","audios":[{"name":null,"artist":null,"url":null,"cover":null,"lrc":null}]},"mermaid":{"enable":false,"version":"9.3.0"}},"version":"2.8.2","navbar":{"auto_hide":false,"color":{"left":"#f78736","right":"#367df7","transparency":35},"width":{"home":"1200px","pages":"1000px"},"links":{"Home":{"path":"/","icon":"fa-regular fa-house"},"Archives":{"path":"/archives","icon":"fa-regular fa-archive"}},"search":{"enable":true,"preload":true}},"page_templates":{"friends_column":2,"tags_style":"blur"},"home":{"sidebar":{"enable":true,"position":"left","first_item":"menu","announcement":null,"show_on_mobile":true,"links":null},"article_date_format":"auto","excerpt_length":200,"categories":{"enable":true,"limit":3},"tags":{"enable":true,"limit":3}},"footerStart":"2022/8/17 11:45:14"};
    window.lang_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
    window.data = {"masonry":false};
  </script>
    
    <!--- Fontawesome Part-->
    
<link rel="stylesheet" href="/fontawesome/fontawesome.min.css">

    
<link rel="stylesheet" href="/fontawesome/brands.min.css">

    
<link rel="stylesheet" href="/fontawesome/solid.min.css">

    
<link rel="stylesheet" href="/fontawesome/regular.min.css">

    
    
    
    
<meta name="generator" content="Hexo 6.3.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>



<body>
	<div class="progress-bar-container">
	

	
	<span class="pjax-progress-bar"></span>
	<!--        <span class="swup-progress-icon">-->
	<!--            <i class="fa-solid fa-circle-notch fa-spin"></i>-->
	<!--        </span>-->
	
</div>

<main class="page-container" id="swup">

	

	<div class="main-content-container flex flex-col justify-between min-h-dvh">
		<div class="main-content-header">
			<header class="navbar-container px-6 md:px-12">
    <div class="navbar-content transition-navbar ">
        <div class="left">
            
                <a class="logo-image h-8 w-8 sm:w-10 sm:h-10 mr-3" href="/">
                    <img src="/images/rabete.jpg" class="w-full h-full rounded-sm">
                </a>
            
            <a class="logo-title" href="/">
                
                xiaoeryu
                
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="desktop">
                <ul class="navbar-list">
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/"
                                        >
                                    <i class="fa-regular fa-house fa-fw"></i>
                                    首页
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/archives"
                                        >
                                    <i class="fa-regular fa-archive fa-fw"></i>
                                    归档
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                    
                        <li class="navbar-item search search-popup-trigger">
                            <i class="fa-solid fa-magnifying-glass"></i>
                        </li>
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fa-solid fa-magnifying-glass"></i>
                    </div>
                
                <div class="icon-item navbar-bar">
                    <div class="navbar-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile sheet -->
    <div class="navbar-drawer h-dvh w-full absolute top-0 left-0 bg-background-color flex flex-col justify-between">
        <ul class="drawer-navbar-list flex flex-col px-4 justify-center items-start">
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/"
                        >
                            <span>
                                首页
                            </span>
                            
                                <i class="fa-regular fa-house fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/archives"
                        >
                            <span>
                                归档
                            </span>
                            
                                <i class="fa-regular fa-archive fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            

            
            
        </ul>

        <div class="statistics flex justify-around my-2.5">
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/tags">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">92</div>
        <div class="label text-third-text-color text-sm">标签</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/categories">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">14</div>
        <div class="label text-third-text-color text-sm">分类</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/archives">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">112</div>
        <div class="label text-third-text-color text-sm">文章</div>
    </a>
</div>
    </div>

    <div class="window-mask"></div>

</header>


		</div>

		<div class="main-content-body transition-fade-up">
			

			<div class="main-content">
				<div class="post-page-container flex relative justify-between box-border w-full h-full">
	<div class="article-content-container">

		<div class="article-title relative w-full">
			
			<div class="w-full flex items-center pt-6 justify-start">
				<h1 class="article-title-regular text-second-text-color tracking-tight text-4xl md:text-6xl font-semibold px-2 sm:px-6 md:px-8 py-3">协同式任务切换</h1>
			</div>
			
		</div>

		
		<div class="article-header flex flex-row gap-2 items-center px-2 sm:px-6 md:px-8">
			<div class="avatar w-[46px] h-[46px] flex-shrink-0 rounded-medium border border-border-color p-[1px]">
				<img src="/images/rabete.jpg">
			</div>
			<div class="info flex flex-col justify-between">
				<div class="author flex items-center">
					<span class="name text-default-text-color text-lg font-semibold">xiaoeryu</span>
					
					<span class="author-label ml-1.5 text-xs px-2 py-0.5 rounded-small text-third-text-color border border-shadow-color-1">Lv5</span>
					
				</div>
				<div class="meta-info">
					<div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="desktop">2022-12-11 22:47</span>
        <span class="mobile">2022-12-11 22:47</span>
        <span class="hover-info">创建</span>
    </span>
    
        <span class="article-date article-meta-item">
            <i class="fa-regular fa-wrench"></i>&nbsp;
            <span class="desktop">2023-10-03 13:13</span>
            <span class="mobile">2023-10-03 13:13</span>
            <span class="hover-info">更新</span>
        </span>
    

    
        <span class="article-categories article-meta-item">
            <i class="fa-regular fa-folders"></i>&nbsp;
            <ul>
                
                
                    
                        
                        <li>
                            <a href="/categories/X86%E6%B1%87%E7%BC%96%EF%BC%9A%E5%AE%9E%E6%A8%A1%E5%BC%8F%E5%88%B0%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F/">X86汇编：实模式到保护模式</a>&nbsp;
                        </li>
                    
                    
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/x86%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/">x86协同式任务切换</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
        <span class="article-pv article-meta-item">
            <i class="fa-regular fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

				</div>
			</div>
		</div>
		

		


		<div class="article-content markdown-body px-2 sm:px-6 md:px-8 pb-8">
			<h2 id="01-任务和任务切换概述"><a href="#01-任务和任务切换概述" class="headerlink" title="01. 任务和任务切换概述"></a>01. 任务和任务切换概述</h2><p>多任务系统中，每个任务都有自己的任务状态段<strong>TSS</strong>和局部描述符表<strong>LDT</strong>，当前任务是由任务寄存器<strong>TR</strong>指示，指向当前任务的任务状态段<strong>TSS</strong>、局部描述符表寄存器<strong>LDTR</strong>也指向当前局部描述符表<strong>LDT</strong>。</p>
<span id="more"></span>

<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ecaeb5708d898aabbeb7135046099657-166832967486710.png" class="">
<p>多任务系统是指可以同时执行两个或者两个以上任务的系统，即使一个任务没有执行完也可以执行下一个任务，多任务切换时<strong>TR</strong>和<strong>LDTR</strong>也要切换到新的任务中。</p>
<p>多任务切换方式：</p>
<ol>
<li><mark>协同式任务切换</mark>：需要当前任务主动请求暂时放弃执行权、或者在通过调用门请求操作系统服务时由操作系统乘机切换到另一个任务中。因此这种方式很依赖于当前执行任务的自律性，当一个任务失控时可能其它任务都得不到执行的机会。</li>
<li><mark>抢占式任务切换</mark>：这种方式可以安装一个定时器中断，在中断信号产生的时候进行任务切换。硬件中断会定时发生，不管处理器在做什么，当产生中断时任务一定会执行切任务换操作，这样所有任务都有平等的执行机会，当一个任务失控时也不会导致其他任务没有机会执行。</li>
</ol>
<p>多任务系统：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/dcc158c41bd25560420ed9ac91e93f1f-16683296748674.png" class="">
<p>任务的组成是灵活的，不一定由不同的特权级组成，也不一定由内核和用户程序组成<br>例如本章将创建三个任务：</p>
<ol>
<li>任务1由单独的内核组成，0特权级。内核除了是一个单独的任务，也是其他任务的全局部分。</li>
<li>任务2由任务2的私有部分和内核组成，其是3特权级。</li>
<li>任务3由任务3的私有部分和内核组成，其也是3特权级。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/5c5fc3fa7fc5bf7b45bc94e33216aae7-16683296748671.png" class=""></li>
</ol>
<p>在本章中，当处理器加电复位之后，进入保护模式之后就直接创建和执行内核的0特权级任务→之后切换到任务2的私有部分→之后切换到内核→之后切换到任务3的私有部分。</p>
<p>每个任务都有自己的状态，特别是当一个任务再执行时，所有段寄存器和通用寄存器都和当前任务息息相关。段寄存器指向当前任务自己的段，通用寄存器保存着当前任务执行的数据和临时结果、标志寄存器保存着当前任务执行产生的各个标志位。</p>
<p>当前任务要切换出去，必须将当前任务的所有状态都保存起来以便将来恢复，这叫做保护现场。被切换到的那个任务也必须恢复到原先它被打断时的状态，叫做恢复现场。</p>
<p>为了保护现场和恢复现场，使用每个任务的<strong>TSS</strong>来保存数据：<strong>CR3</strong>和分页有关。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/9338fcfaa209df58ccd8cec9796059a9-16683296748672.png" class="">
<p>保存当前任务的现场：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/00af7da67920361a23086cf9741893e9-16683296748673.png" class="">
<p>恢复目标任务的现场：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/da3677ea1fab46deb7cd37f467754371-16683296748675.png" class="">
<p>恢复之后被切换到的任务变成当前任务。</p>
<h2 id="02-内核任务的创建和当前I-x2F-O特权级LOPL"><a href="#02-内核任务的创建和当前I-x2F-O特权级LOPL" class="headerlink" title="02. 内核任务的创建和当前I/O特权级LOPL"></a>02. 内核任务的创建和当前I/O特权级LOPL</h2><p>本章程序：<br>引导程序：<strong>c13_mbr0.asm</strong>，加载执行内核。<br>内核程序：<strong>c15_core0.asm</strong>，加了新的内容。<br>用户程序：<strong>c15_app0.asm</strong>，加了新的内容。</p>
<p><strong>I/O许可位图</strong>，之前讲过特权指令，即只有<strong>0特权级</strong>才能执行的指令。但是有一些低特权级的程序也需要使用这些指令。<br>如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/d0448a72f4c8a35a954f62f55b5e880c-16683296748676.png" class="">
<p>为了控制哪些任务能够访问硬件端口，需要用到标志寄存器EFLAGS：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/c00656182066503226da7f091421e2e7-16683296748679.png" class="">
<p>当前特权级<strong>CPL</strong>若高于<strong>IOPL（I/O Privilege Level)<strong>，数值上</strong>CPL ≤ IOPL</strong>，则表示所有<strong>I/O</strong>访问都是被允许的。</p>
<h2 id="03-I-x2F-O特权级的修改和POPF指令"><a href="#03-I-x2F-O特权级的修改和POPF指令" class="headerlink" title="03. I/O特权级的修改和POPF指令"></a>03. I/O特权级的修改和POPF指令</h2><p>标志寄存器中的标志是会随着任务的执行而改变的，比如：<strong>ZF、CF</strong>；有些则需要特定的指令来改变，比如<strong>DF</strong>。但是<strong>IOPL</strong>不会自动随程序修改，也没有特定的指令来修改，修改<strong>IOPL</strong>需要执行以下操作：</p>
<ol>
<li><p>先将标志寄存器压栈</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/2e1ea44696421df22f3de6cd05dc5fb3-16683296748677.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/f6e06e2f34d89404d6261e892f7ce7a8-16683296748678.png" class="">
</li>
<li><p>然后对栈中<strong>IOPL</strong>内容进行修改</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/b877b21342d7e33e4f1c856eb51594ae-166832967486711.png" class="">
<p>将<strong>IOPL</strong>修改为01。</p>
</li>
<li><p>最后将栈中修改后的内容弹出到寄存器。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/91176a8596b09cbe9383b772a9bf48a4-166832967486712.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/d251cfc7ef40c8161ed1675c33700695-166832967486714.png" class=""></li>
</ol>
<h2 id="04-任务的用户态和内核态"><a href="#04-任务的用户态和内核态" class="headerlink" title="04. 任务的用户态和内核态"></a>04. 任务的用户态和内核态</h2><p>每个任务都有<strong>TSS</strong>，其中保存了<strong>EFLAGS</strong>，有<strong>IOPL</strong>字段。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/acf15bb6736f7490e9dcfd1a55b9f4d8-166832967486713.png" class="">
<p>多任务系统特点：可以在内核任务和用户任务之间来回切换、也可以再两个任务之间来回切换。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/718352e49749237d68e1c4ba568a88a1-166832967486715.png" class="">
<p>每当一个任务被切换回后台时，它与之相关的状态都会保存再它的<strong>TSS</strong>中，当它恢复时，会从它的<strong>TSS</strong>中将各种状态恢复到处理器中。显然每个任务都受自己的<strong>IOPL</strong>所限制。</p>
<p>每个任务都可以对自己的标志和状态进行修改，比如标志寄存器中的内容，需要使用如下指令进行压栈、修改、再出栈返回到标志寄存器中。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/41bea40aa66420d64e1fdbac1aa21dc5-166832967486716.png" class="">
<p>其中<mark>pushf、pushfd</mark>在任务特权级下均可执行，但是<mark>popf、popfd</mark>执行时标志寄存器中的有些标志位是否会受到影响（如IOPL字段)是否能被修改则取决于当前特权级<strong>CPL</strong>：</p>
<ol>
<li>CPL为0，那么执行<mark>popf、popfd</mark>指令时，标志寄存器的<mark>IOPL</mark>字段会被修改；</li>
<li>CPL为1，那么执行<mark>popf、popfd</mark>指令时，标志寄存器的<mark>IOPL</mark>字段类似于<strong>只读</strong>，不会受到影响；</li>
</ol>
<p>即低特权级指令无法使用<mark>popf、popfd</mark>指令修改<mark>IOPL</mark>字段。<mark>popf、popfd</mark>并不是特权指令，特权指令是只能在0特权级下执行，<mark>popf、popfd</mark>指令在低特权级下也可以执行，只不过在低特权级下执行时一些标志位不受其影响。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/bbef20148f7a47065143878328f53ea9-166832967486717.png" class="">
<p>内核任务只能在内核态执行，用户任务可以在内核态和用户态中执行。</p>
<h2 id="05-I-x2F-O许可位串和TSS的I-x2F-O许可位映射区"><a href="#05-I-x2F-O许可位串和TSS的I-x2F-O许可位映射区" class="headerlink" title="05. I/O许可位串和TSS的I/O许可位映射区"></a>05. I/O许可位串和TSS的I/O许可位映射区</h2><img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/9e36bd13dc99727a853f3386f567ae47-166832967486718.png" class="">
<p>当前<strong>CPL</strong>高于等于<strong>IOPL</strong>（数值上CPL ≤ IOPL），则所有<strong>I/O</strong>操作都是被允许的；<br>当前<strong>CPL</strong>低于<strong>IOPL</strong>（数值上CPL ≥ IOPL），也并非意味着所有<strong>I/O</strong>操作都是不被允许的，而是需要进一步指定哪些允许，哪些不允许。在输入输出（I/O许可位串）中指定。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/49ba689fa14560fdabc76ff3a3d24938-166832967486819.png" class="">
<p>TSS中基本长度是104字节，当然也可以包括I/O许可位映射区</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ac052aceeb0186b956372984e4100f67-166832967486820.png" class="">
<p><strong>TSS</strong>描述符及其布局：其中段界限是包括<strong>I/O许可位映射区</strong>的。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/dc6036897ff49aeebec6d08d4e222444-166832967486821.png" class="">
<p>其中<strong>I/O许可位的偏移M</strong>若大于<strong>TSS</strong>描述符的段界限，则意味着没有<strong>I/O许可位</strong>。在这种情况下，如果当前<strong>CPL ≥ IOPL</strong>，就意味着必须检查<strong>I/O许可位串</strong>，但是没有<strong>I/O</strong>许可位串就意味着不允许访问硬件端口，执行任何硬件I/O指令都会引发处理器的异常中断。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/0bd3c3d8808b9315f7a79ceb4e3209a5-166832967486822.png" class="">

<p>处理器检查<strong>I/O</strong>许可位方法如下：</p>
<ol>
<li>先根据端口号计算它在<strong>I/O</strong>许可位映射区的哪个字节中；</li>
<li>然后读取该字节，并测试那个<strong>byte</strong>位，<br>如<strong>out 0x09, al</strong>指令：端口<strong>0x09</strong>位于第二个<strong>byte</strong>，而且位于第二个字节的<strong>位1</strong>.处理器读取并测试这个<strong>byte位</strong>是0还是1来决定是否允许执行这个<strong>out</strong>指令。</li>
</ol>
<p>I/O端口是按照字节编址的，即每个端口只能用来读取一个字节的数据，那些多字节的端口其实是合并了几个端口组成一个多字节端口的：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ff8895b5ee0a42a472ea2ed58c2914cc-166832967486823.png" class="">
<p>由于<strong>I/O端口</strong>是按照字节编址的原因，当处理器执行一个字或者双字的<strong>I/O</strong>指令时，会检查许可位串中的2个或者4个连续的<strong>byte</strong>，而且要求它们必须都是0，否则引发异常中断。</p>
<p>麻烦在于这些连续的<strong>byte</strong>有可能是跨字节的，即一些<strong>byte</strong>位于前一个字节有些位于后一个字节，<br>如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/67391e2a303f4dec1de5a884b13b9704-166832967486824.png" class="">
<p>所以处理器每次都从<strong>I/O许可位映射区</strong>读取2个连续的字节，而不是1个字节。</p>
<p>这种操作方式也导致了另一个问题，即要检查的<strong>byte</strong>如果在最后一个字节中这样的读操作就会导致越界。为了防止这种情况发生处理器要求<strong>I/O许可位映射区</strong>最后必须附加一个额外的字节，其值为<strong>0xFF</strong>。<br>如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/ef823bfa7f5ca793b66e36664ede8de5-166832967486825.png" class="">
<p>若<strong>I/O许可映射区</strong>本身只有11个字节，除去最后一位<strong>0xFF</strong>，只剩下10个字节，那么只能映射80个端口，访问更高地址的端口（高于79号端口）将引发异常中断。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/1ff6610bde8ec0dea0d453b3b7f8513b-166832967486826.png" class="">

<h2 id="06-任务切换的方法以及内核任务的确立"><a href="#06-任务切换的方法以及内核任务的确立" class="headerlink" title="06. 任务切换的方法以及内核任务的确立"></a>06. 任务切换的方法以及内核任务的确立</h2><p>内核本身要当作一个独立的任务，内核正在执行现在要为其补一个合法的手续。<br>创建内核的<strong>TSS</strong>，接着要在<strong>TSS</strong>中填充一些内容，在任务切换之前提前准备好。</p>
<p>设置内核任务的<strong>TSS</strong>：</p>
<pre><code class="assembly">    ;为内核任务的TSS分配内存空间
    mov ecx,104                        ;为该任务的TSS分配内存
    call sys_routine_seg_sel:allocate_memory
    mov [es:esi+0x14],ecx              ;在内核TCB中保存TSS基地址
    
    ;在程序管理器的TSS中设置必要的项目 
    mov word [es:ecx+96],0             ;没有LDT。处理器允许没有LDT的任务。
    mov word [es:ecx+102],103          ;没有I/O位图。0特权级事实上不需要。
    mov word [es:ecx+0],0              ;反向链=0
    mov dword [es:ecx+28],0            ;登记CR3(PDBR)
    mov word [es:ecx+100],0            ;T=0
                                       ;不需要0、1、2特权级堆栈。0特级不
                                       ;会向低特权级转移控制。
</code></pre>
<ol>
<li>内核任务不需要<strong>LDT</strong>，所以在内核<strong>TSS</strong>偏移<strong>0x96</strong>的地方填写数字0即可；</li>
<li>内核任务也不需要<strong>I/O许可位映射区</strong>，内核是0特权级，始终可以进行所有<strong>I/O</strong>操作。这里偏移填写<strong>103</strong>为内核<strong>TSS</strong>的界限值，即表示保存在<strong>I/O许可位映射区</strong>；</li>
<li>反向链相关，硬件任务切换在64位处理器上不再支持，除非以兼容模式允许运行。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/3135d4b33d7c48116f2f6bf55cd66f78-166832967486828.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/a9ab3530a487a16867948ba0c25cf83d-166832967486827.png" class=""></li>
</ol>
<ul>
<li>用<strong>CALL</strong>指令发起任务切换时，任务之间会形成一个任务链，可以通过任务链反向切换到原来的任务中。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/001d7c469b6f0b1abc71c9e0f9713cd5-166832967486831.png" class=""></li>
<li>所以在<strong>TSS</strong>中偏移为0的位置，置零即可：<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/39a8a20c8af636fab0a1f4563c1b9bad-166832967486829.png" class=""></li>
</ul>
<ol start="4">
<li>和分页相关的位<strong>暂时先清0</strong><img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/77fb6ce6c965082e6d67af30c2154161-166832967486830.png" class=""></li>
<li>设置<strong>T位</strong>为0，因为内核特权级为0，不会向低特权级实施控制转移。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/b6b82d293be287f02f228efc14995d42-166832967486834.png" class=""></li>
</ol>
<p>创建内核任务的<strong>TSS</strong>莫舒服，安装到<strong>GDT</strong>中：</p>
<pre><code class="assembly">    ;创建TSS描述符，并安装到GDT中 
    mov eax,ecx                        ;TSS的起始线性地址
    mov ebx,103                        ;段长度（界限）
    mov ecx,0x00008900                 ;TSS描述符，特权级0
    call sys_routine_seg_sel:make_seg_descriptor
    call sys_routine_seg_sel:set_up_gdt_descriptor
    mov word [es:esi+0x18],cx          ;登记TSS选择子到TCB
    mov word [es:esi+0x04],0xffff      ;任务的状态为“忙”
    
    ;任务寄存器TR中的内容是任务存在的标志，该内容也决定了当前任务是谁。
    ;下面的指令为当前正在执行的0特权级任务“程序管理器”后补手续（TSS）。
    ltr cx
    
    ;现在可认为“程序管理器”任务正执行中
    mov ebx,core_msg1
    call sys_routine_seg_sel:put_string
</code></pre>
<h2 id="07-用户任务的创建和初始化"><a href="#07-用户任务的创建和初始化" class="headerlink" title="07. 用户任务的创建和初始化"></a>07. 用户任务的创建和初始化</h2><p><strong>TCB</strong>中偏移为<strong>0x04</strong>位置：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/9be2c12d07936a3550453e7f55b65580-166832967486832.png" class="">
<p>任务状态为<mark>0表示就绪</mark>、为<mark>0xFFFF</mark>表示忙状态、为<mark>0x3333</mark>表示任务已经终止。</p>
<p>为用户任务创建<strong>TCB</strong>：</p>
<pre><code class="assembly">    ;以下开始创建用户任务
    mov ecx,0x46
    call sys_routine_seg_sel:allocate_memory
    mov word [es:ecx+0x04],0           ;任务状态：就绪
    call append_to_tcb_link            ;将此TCB添加到TCB链中
</code></pre>
<p>之后加载和重定位用户程序，并将其创建为任务。</p>
<pre><code class="assembly">    push dword 50                      ;用户程序位于逻辑50扇区
    push ecx                           ;压入任务控制块起始线性地址 
    
    call load_relocate_program 
</code></pre>
<p>在例程<strong>load_relocate_program</strong>中：</p>
<ol>
<li><p>创建<strong>LDT</strong>；</p>
</li>
<li><p>加载用户程序；</p>
</li>
<li><p>创建用户程序每个段的描述符，并将其安装到<strong>LDT</strong>中；</p>
</li>
<li><p>重定位用户程序的符号地址检索表<strong>SALT</strong>，本章在<strong>SALT</strong>中新增一个条目<mark>InitTaskSwitch</mark>用于任务切换。</p>
</li>
<li><p>创建<strong>0、1、2特权级</strong>的栈段描述符及其选择子，为通过调用门转移控制而准备的；</p>
</li>
<li><p>在<strong>GDT</strong>中登记<strong>LDT</strong>描述符；</p>
</li>
<li><p>创建用户任务的<strong>TSS</strong>；</p>
</li>
<li><p>在用户任务的<strong>TSS</strong>中登记相关的信息，参考<strong>TSS结构</strong>；</p>
<ol>
<li>填写任务的反向链</li>
<li>填写<strong>0、1、2特权级</strong>的栈段选择子和栈指针</li>
<li>登记<strong>LDT</strong>选择子</li>
<li>登记<strong>I/O许可位映射区</strong>偏移</li>
<li>登记T标志（TSS+100的调试位）</li>
<li>登记<strong>CR3</strong>（和分页有关）</li>
<li>登记其它信息<ol>
<li>以前内核不是单独的任务而是用户任务的私有部分，所以用户程序加载之后模拟调用门返回，从任务的全局部分返回任务的私有部分。本章中内核为一个独立的任务，是正在执行的任务，所以当我们创建了用户任务之后将使用任务切换的方式从内核任务切换到用户任务。</li>
<li>切换到用户任务时，一定会从用户任务的<strong>TSS</strong>中恢复现场，即使是用户任务的第一次执行，为了确保用户任务的第一次切换成功，需要在用户任务的<strong>TSS</strong>中设置哪些内容呢？</li>
<li>首先是<mark>0、1、2特权级</mark>的栈段选择子和栈指针；接着是通用寄存器的内容，一般都是运行时自动设置，也有一些需要单独设置（如<strong>EFLAGS</strong>中的<strong>LOPL</strong>字段、<strong>EIP</strong>要设置为用户任务入口点的偏移量）。</li>
<li>段寄存器的内容，可以提前设置也可以在程序中用指令初始化，<strong>CS</strong>必须在这里设置为用户程序入口点的代码段选择子。</li>
<li>若用户任务有<strong>LDT</strong>，则需要设置<strong>LDT</strong>段选择子。</li>
<li>若用户任务有<strong>I/O许可位映射区</strong>，则需要设置映射区的偏移。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/a65a44442dca24365dd94997b837543d-166832967486833.png" class=""></li>
</ol>
</li>
</ol>
</li>
<li><p>创建用户任务的<strong>TSS</strong>描述符，并将其安装在<strong>GDT</strong>中，安装之后在<strong>CX</strong>中返回<strong>TSS</strong>的选择子，将其登记在用户任务控制块<strong>TCB</strong>中。</p>
</li>
<li><p>从例程<strong>load_relocate_program</strong>中返回。</p>
</li>
</ol>
<p>创建一个用户任务之后还可以创建其它任务：</p>
<pre><code class="assembly">    ;可以创建更多的任务，例如：
    ;mov ecx,0x46
    ;call sys_routine_seg_sel:allocate_memory
    ;mov word [es:ecx+0x04],0           ;任务状态：空闲
    ;call append_to_tcb_link            ;将此TCB添加到TCB链中
    
    ;push dword 50                      ;用户程序位于逻辑50扇区
    ;push ecx                           ;压入任务控制块起始线性地址
    
    ;call load_relocate_program
</code></pre>
<p>之后就是任务管理的循环，用来发起内核任务到用户任务的切换、回收已经终止任务的资源、也可以选择创建新的任务。</p>
<pre><code class="assembly">.do_switch:
    ;主动切换到其它任务，给它们运行的机会
    call sys_routine_seg_sel:initiate_task_switch
    
    mov ebx,core_msg2
    call sys_routine_seg_sel:put_string
    
    ;这里可以添加创建新的任务的功能，比如：
    ;mov ecx,0x46
    ;call sys_routine_seg_sel:allocate_memory
    ;mov word [es:ecx+0x04],0           ;任务状态：空闲
    ;call append_to_tcb_link            ;将此TCB添加到TCB链中
    
    ;push dword 50                      ;用户程序位于逻辑50扇区
    ;push ecx                           ;压入任务控制块起始线性地址
    
    ;call load_relocate_program
    
    ;清理已经终止的任务，并回收它们占用的资源
    call sys_routine_seg_sel:do_task_clean
    
    mov eax,[tcb_chain]
.find_ready:
    cmp word [es:eax+0x04],0x0000      ;还有处于就绪状态的任务？
    jz .do_switch                      ;有，继续执行任务切换
    mov eax,[es:eax]
    or eax,eax                         ;还有用户任务吗？
    jnz .find_ready                    ;一直搜索到链表尾部
    
    ;已经没有可以切换的任务，停机
    mov ebx,core_msg3
    call sys_routine_seg_sel:put_string
    hlt
</code></pre>
<h2 id="08-简单的任务调度和切换策略"><a href="#08-简单的任务调度和切换策略" class="headerlink" title="08. 简单的任务调度和切换策略"></a>08. 简单的任务调度和切换策略</h2><p>接上一节<br>所有的任务都是平等的参与任务切换，切换到用户任务时做的是自己的私事，切换到内核任务时做的是管理整个系统。</p>
<p>使用例程<strong>initiate_task_switch</strong>进行任务切换，从任务链表中找到下一个就绪状态的任务，进行切换。<strong>tcb_chain</strong>中记录每个任务的<strong>TCB</strong>，其中有下一个任务的地址和这个任务的状态（<mark>0表示就绪</mark>、为<mark>0xFFFF</mark>表示忙状态、为<mark>0x3333</mark>表示任务已经终止）。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/d41c66dea07be9c7e5c05748e71cde5a-166832967486835.png" class="">
<p>任务调度策略：顺着<strong>TCB</strong>链表找到当前正在执行的任务，继续往后再找到一个就绪的任务，然后切换到这个就绪的任务。切换之后将任务的状态都进行改变（忙改为就绪、就绪改为忙）。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/bd85ede83741a94c9123371a21ebb6db-166832967486836.png" class="">
<p><mark>特殊情况1</mark>：如上图，如果系统只有一个任务则不执行切换。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/1dcaf8e5bb7db4a65880bcd7c3e953af-166832967486837.png" class="">
<p><mark>特殊情况2</mark>：如上图，每次都是从<strong>tcb_chain</strong>链表头部开始搜索，先找到忙的任务再往后找到就绪的任务。如果忙的任务处于链表尾部，则需要返回链表头部从头开始查找状态为就绪的任务，这样的轮转能保证每个任务都能有公平的轮转机会。</p>
<h2 id="09-遍历TCB链表寻找忙任务和就绪任务"><a href="#09-遍历TCB链表寻找忙任务和就绪任务" class="headerlink" title="09. 遍历TCB链表寻找忙任务和就绪任务"></a>09. 遍历TCB链表寻找忙任务和就绪任务</h2><p>本节是分析例程initiate_task_switch，具体看代码和视频。</p>
<h2 id="10-通过JMP-FAR执行任务切换的过程"><a href="#10-通过JMP-FAR执行任务切换的过程" class="headerlink" title="10. 通过JMP FAR执行任务切换的过程"></a>10. 通过JMP FAR执行任务切换的过程</h2><p>上一节中找到了<strong>状态忙的任务</strong>和<strong>状态就绪的任务</strong>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/107c4944925dba82aa648298b8137c5d-166832967486838.png" class="">
<p>在64位处理器上不再提供硬件任务切换，操作系统也不适用硬件任务切换</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/01869b2eb6e10f8d5cae7caf15c17de4-166832967486839.png" class="">
<p>使用**jmp far [edi+0x14]**指令进行任务切换：</p>
<ul>
<li><strong>EDI</strong>保存就绪任务的<strong>TCB</strong>线性地址，<strong>TCB</strong>偏移0x14的地方，存放<strong>TSS</strong>的基地址和16位<strong>TSS</strong>选择子；</li>
<li>处理器执行这条指令时使用<strong>DS</strong>描述符高速缓存器中的基地址 + 段内偏移（EDI + 0X14），取出6个字节，假定它们是段选择子和段内偏移；当处理器发现后两个字节保存的段选择子是<strong>TSS</strong>选择子，则前面的4个字节段内偏移量会被忽略（实际上我们在这里保存的是TSS基地址）。</li>
<li>用这个选择子到<strong>GDT</strong>中寻找对应的描述符，处理器发现这是<strong>TSS</strong>描述符，就知道需要发起任务切换</li>
<li>保存旧任务的状态<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/fc427ef9510f44f38d1e12e15be5648a-166832967486840.png" class=""></li>
</ul>
<p>当前<strong>CS</strong>指向内核公共例程段，<strong>EIP</strong>指向下一条指令，则保存状态时，<strong>CS</strong>和<strong>EIP</strong>保存的是上述值。</p>
<ul>
<li>设置新任务的状态<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/70577bd2c49d9b5eb881ad75b116415d-166832967486841.png" class=""></li>
</ul>
<p>第一次是从内核任务切换到用户任务，在创建用户任务时，已经在用户任务的<strong>TSS</strong>中登记了各种信息，包括0、1、2三个特权级的栈段选择子<strong>SS</strong>和栈指针<strong>ESP</strong>，接着登记<strong>LDT</strong>选择子，之后是入口点信息，包括<strong>CS</strong>、<strong>EIP</strong>。一旦从用户任务的<strong>TSS</strong>中恢复这些信息，处理器就转移到了用户程序执行。</p>
<h2 id="11-内核任务与用户任务轮流执行的过程"><a href="#11-内核任务与用户任务轮流执行的过程" class="headerlink" title="11. 内核任务与用户任务轮流执行的过程"></a>11. 内核任务与用户任务轮流执行的过程</h2><p>看视频、代码即可，主要讲解了从内核任务切换到用户任务的执行流程。</p>
<h2 id="12-任务的中止和清理"><a href="#12-任务的中止和清理" class="headerlink" title="12. 任务的中止和清理"></a>12. 任务的中止和清理</h2><p>看视频、代码即可，主要讲解了从用户任务切换到内核任务的执行流程，其中会对任务进行清理。</p>
<p>虚拟机执行结果：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/image-20221113165458658.png" class="" title="image-20221113165458658">

		</div>

		
		<div class="post-copyright-info w-full my-8 px-2 sm:px-6 md:px-8">
			<div class="article-copyright-info-container">
    <ul>
        <li><strong>标题:</strong> 协同式任务切换</li>
        <li><strong>作者:</strong> xiaoeryu</li>
        <li><strong>创建于
                :</strong> 2022-12-11 22:47:00</li>
        
            <li>
                <strong>更新于
                    :</strong> 2023-10-03 13:00:13
            </li>
        
        <li>
            <strong>链接:</strong> https://github.com/xiaoeryu/2022/12/11/29-协同式任务切换/
        </li>
        <li>
            <strong>
                版权声明:
            </strong>
            

            
                本文章采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0">CC BY-NC-SA 4.0</a> 进行许可。
            
        </li>
    </ul>
</div>

		</div>
		

		
		<ul class="post-tags-box text-lg mt-1.5 flex-wrap justify-center flex md:hidden">
			
			<li class="tag-item mx-0.5">
				<a href="/tags/x86%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/">#x86协同式任务切换</a>&nbsp;
			</li>
			
		</ul>
		

		

		
		<div class="article-nav my-8 flex justify-between items-center px-2 sm:px-6 md:px-8">
			
			<div class="article-prev border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="prev" rel="prev" href="/2022/12/11/30-%E4%B8%AD%E6%96%AD%E5%92%8C%E5%BC%82%E5%B8%B8%E7%9A%84%E5%A4%84%E7%90%86%E4%B8%8E%E6%8A%A2%E5%8D%A0%E5%BC%8F%E5%A4%9A%E4%BB%BB%E5%8A%A1/">
					<span class="left arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-left"></i>
					</span>
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">中断和异常的处理与抢占式多任务</span>
						<span class="post-nav-item">上一篇</span>
					</span>
				</a>
			</div>
			
			
			<div class="article-next border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="next" rel="next" href="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/">
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">特权级和特权级保护</span>
						<span class="post-nav-item">下一篇</span>
					</span>
					<span class="right arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-right"></i>
					</span>
				</a>
			</div>
			
		</div>
		


		
		<div class="comment-container px-2 sm:px-6 md:px-8 pb-8">
			<div class="comments-container mt-10 w-full ">
    <div id="comment-anchor" class="w-full h-2.5"></div>
    <div class="comment-area-title w-full my-1.5 md:my-2.5 text-xl md:text-3xl font-bold">
        评论
    </div>
    

        
            


        
    
</div>

		</div>
		
	</div>

	
	<div class="toc-content-container">
		<div class="post-toc-wrap">
	<div class="post-toc">
		<div class="toc-title">目录</div>
		<div class="page-title">协同式任务切换</div>
		<ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#01-%E4%BB%BB%E5%8A%A1%E5%92%8C%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2%E6%A6%82%E8%BF%B0"><span class="nav-text">01. 任务和任务切换概述</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#02-%E5%86%85%E6%A0%B8%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E5%92%8C%E5%BD%93%E5%89%8DI-x2F-O%E7%89%B9%E6%9D%83%E7%BA%A7LOPL"><span class="nav-text">02. 内核任务的创建和当前I&#x2F;O特权级LOPL</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#03-I-x2F-O%E7%89%B9%E6%9D%83%E7%BA%A7%E7%9A%84%E4%BF%AE%E6%94%B9%E5%92%8CPOPF%E6%8C%87%E4%BB%A4"><span class="nav-text">03. I&#x2F;O特权级的修改和POPF指令</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#04-%E4%BB%BB%E5%8A%A1%E7%9A%84%E7%94%A8%E6%88%B7%E6%80%81%E5%92%8C%E5%86%85%E6%A0%B8%E6%80%81"><span class="nav-text">04. 任务的用户态和内核态</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#05-I-x2F-O%E8%AE%B8%E5%8F%AF%E4%BD%8D%E4%B8%B2%E5%92%8CTSS%E7%9A%84I-x2F-O%E8%AE%B8%E5%8F%AF%E4%BD%8D%E6%98%A0%E5%B0%84%E5%8C%BA"><span class="nav-text">05. I&#x2F;O许可位串和TSS的I&#x2F;O许可位映射区</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#06-%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2%E7%9A%84%E6%96%B9%E6%B3%95%E4%BB%A5%E5%8F%8A%E5%86%85%E6%A0%B8%E4%BB%BB%E5%8A%A1%E7%9A%84%E7%A1%AE%E7%AB%8B"><span class="nav-text">06. 任务切换的方法以及内核任务的确立</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#07-%E7%94%A8%E6%88%B7%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E5%92%8C%E5%88%9D%E5%A7%8B%E5%8C%96"><span class="nav-text">07. 用户任务的创建和初始化</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#08-%E7%AE%80%E5%8D%95%E7%9A%84%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E5%92%8C%E5%88%87%E6%8D%A2%E7%AD%96%E7%95%A5"><span class="nav-text">08. 简单的任务调度和切换策略</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#09-%E9%81%8D%E5%8E%86TCB%E9%93%BE%E8%A1%A8%E5%AF%BB%E6%89%BE%E5%BF%99%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%B0%B1%E7%BB%AA%E4%BB%BB%E5%8A%A1"><span class="nav-text">09. 遍历TCB链表寻找忙任务和就绪任务</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#10-%E9%80%9A%E8%BF%87JMP-FAR%E6%89%A7%E8%A1%8C%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2%E7%9A%84%E8%BF%87%E7%A8%8B"><span class="nav-text">10. 通过JMP FAR执行任务切换的过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#11-%E5%86%85%E6%A0%B8%E4%BB%BB%E5%8A%A1%E4%B8%8E%E7%94%A8%E6%88%B7%E4%BB%BB%E5%8A%A1%E8%BD%AE%E6%B5%81%E6%89%A7%E8%A1%8C%E7%9A%84%E8%BF%87%E7%A8%8B"><span class="nav-text">11. 内核任务与用户任务轮流执行的过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#12-%E4%BB%BB%E5%8A%A1%E7%9A%84%E4%B8%AD%E6%AD%A2%E5%92%8C%E6%B8%85%E7%90%86"><span class="nav-text">12. 任务的中止和清理</span></a></li></ol>

	</div>
</div>
	</div>
	
</div>
			</div>

			
		</div>

		<div class="main-content-footer">
			<footer class="footer mt-5 py-5 h-auto text-base text-third-text-color relative border-t-2 border-t-border-color">
    <div class="info-container py-3 text-center">
        
        <div class="text-center">
            &copy;
            
              <span>2022</span>
              -
            
            2025&nbsp;&nbsp;<i class="fa-solid fa-heart fa-beat" style="--fa-animation-duration: 0.5s; color: #f54545"></i>&nbsp;&nbsp;<a href="/">xiaoeryu</a>
            
                
                <p class="post-count space-x-0.5">
                    <span>
                        共撰写了 112 篇文章
                    </span>
                    
                </p>
            
        </div>
        
            <script data-swup-reload-script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="relative text-center lg:absolute lg:right-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-right">
                
                    <span id="busuanzi_container_site_uv" class="lg:!block">
                        <span class="text-sm">访问人数</span>
                        <span id="busuanzi_value_site_uv"></span>
                    </span>
                
                
                    <span id="busuanzi_container_site_pv" class="lg:!block">
                        <span class="text-sm">总访问量</span>
                        <span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        <div class="relative text-center lg:absolute lg:left-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-left">
            <span class="lg:block text-sm">由 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="relative top-[2px] inline-block align-baseline" version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1rem" height="1rem" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path fill="#0E83CD" d="M256.4,25.8l-200,115.5L56,371.5l199.6,114.7l200-115.5l0.4-230.2L256.4,25.8z M349,354.6l-18.4,10.7l-18.6-11V275H200v79.6l-18.4,10.7l-18.6-11v-197l18.5-10.6l18.5,10.8V237h112v-79.6l18.5-10.6l18.5,10.8V354.6z"/></svg><a target="_blank" class="text-base" href="https://hexo.io">Hexo</a> 驱动</span>
            <span class="text-sm lg:block">主题&nbsp;<a class="text-base" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v2.8.2</a></span>
        </div>
        
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
            <script data-swup-reload-script>
                try {
                    function odometer_init() {
                    const elements = document.querySelectorAll('.odometer');
                    elements.forEach(el => {
                        new Odometer({
                            el,
                            format: '( ddd).dd',
                            duration: 200
                        });
                    });
                    }
                    odometer_init();
                } catch (error) {}
            </script>
        
        
        
    </div>  
</footer>
		</div>
	</div>

	
	<div class="post-tools">
		<div class="post-tools-container">
	<ul class="article-tools-list">
		<!-- TOC aside toggle -->
		
		<li class="right-bottom-tools page-aside-toggle">
			<i class="fa-regular fa-outdent"></i>
		</li>
		

		<!-- go comment -->
		
		<li class="go-comment">
			<i class="fa-regular fa-comments"></i>
		</li>
		
	</ul>
</div>
	</div>
	

	<div class="right-side-tools-container">
		<div class="side-tools-container">
	<ul class="hidden-tools-list">
		<li class="right-bottom-tools tool-font-adjust-plus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-plus"></i>
		</li>

		<li class="right-bottom-tools tool-font-adjust-minus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-minus"></i>
		</li>

		<li class="right-bottom-tools tool-dark-light-toggle flex justify-center items-center">
			<i class="fa-regular fa-moon"></i>
		</li>

		<!-- rss -->
		

		

		<li class="right-bottom-tools tool-scroll-to-bottom flex justify-center items-center">
			<i class="fa-regular fa-arrow-down"></i>
		</li>
	</ul>

	<ul class="visible-tools-list">
		<li class="right-bottom-tools toggle-tools-list flex justify-center items-center">
			<i class="fa-regular fa-cog fa-spin"></i>
		</li>
		
		<li class="right-bottom-tools tool-scroll-to-top flex justify-center items-center">
			<i class="arrow-up fas fa-arrow-up"></i>
			<span class="percent"></span>
		</li>
		
		
	</ul>
</div>
	</div>

	<div class="image-viewer-container">
	<img src="">
</div>

	
	<div class="search-pop-overlay">
	<div class="popup search-popup">
		<div class="search-header">
			<span class="search-input-field-pre">
				<i class="fa-solid fa-keyboard"></i>
			</span>
			<div class="search-input-container">
				<input autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="站内搜索您需要的内容..." spellcheck="false" type="search" class="search-input">
			</div>
			<span class="popup-btn-close">
				<i class="fa-solid fa-times"></i>
			</span>
		</div>
		<div id="search-result">
			<div id="no-result">
				<i class="fa-solid fa-spinner fa-spin-pulse fa-5x fa-fw"></i>
			</div>
		</div>
	</div>
</div>
	

</main>



<script src="/js/build/libs/Swup.min.js"></script>

<script src="/js/build/libs/SwupSlideTheme.min.js"></script>

<script src="/js/build/libs/SwupScriptsPlugin.min.js"></script>

<script src="/js/build/libs/SwupProgressPlugin.min.js"></script>

<script src="/js/build/libs/SwupScrollPlugin.min.js"></script>

<script src="/js/build/libs/SwupPreloadPlugin.min.js"></script>

<script>
    const swup = new Swup({
        plugins: [
            new SwupScriptsPlugin({
                optin: true,
            }),
            new SwupProgressPlugin(),
            new SwupScrollPlugin({
                offset: 80,
            }),
            new SwupSlideTheme({
                mainElement: ".main-content-body",
            }),
            new SwupPreloadPlugin(),
        ],
        containers: ["#swup"],
    });
</script>




	
<script src="/js/build/tools/imageViewer.js" type="module"></script>

<script src="/js/build/utils.js" type="module"></script>

<script src="/js/build/main.js" type="module"></script>

<script src="/js/build/layouts/navbarShrink.js" type="module"></script>

<script src="/js/build/tools/scrollTopBottom.js" type="module"></script>

<script src="/js/build/tools/lightDarkSwitch.js" type="module"></script>

<script src="/js/build/layouts/categoryList.js" type="module"></script>



    
<script src="/js/build/tools/localSearch.js" type="module"></script>




    
<script src="/js/build/tools/codeBlock.js" type="module"></script>




    
<script src="/js/build/layouts/lazyload.js" type="module"></script>




    
<script src="/js/build/tools/runtime.js"></script>

    
<script src="/js/build/libs/odometer.min.js"></script>

    
<link rel="stylesheet" href="/assets/odometer-theme-minimal.css">




  
<script src="/js/build/libs/Typed.min.js"></script>

  
<script src="/js/build/plugins/typed.js" type="module"></script>








    
<script src="/js/build/libs/anime.min.js"></script>





    
<script src="/js/build/tools/tocToggle.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/layouts/toc.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/plugins/tabs.js" type="module" data-swup-reload-script=""></script>




<script src="/js/build/libs/moment-with-locales.min.js" data-swup-reload-script=""></script>


<script src="/js/build/layouts/essays.js" type="module" data-swup-reload-script=""></script>





	
</body>

</html>